import { Ref, useCallback, useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { DomAdapter, styling } from "splittings-dom/dist/es/splittings-dom";
import "splittings-dom/dist/es/splittings-dom.css";
import { Slot, Workspaces } from "splittings/dist/es/splittings";
import { MyDomAdapter } from "./MyDomAdapter";
import ErrorBoundary from "antd/es/alert/ErrorBoundary";

export * from "splittings-dom/dist/es/splittings-dom";
export * from "splittings/dist/es/splittings";
export interface IWorkspacesViewRef {
  workspaces: Workspaces<DomAdapter> | null
}
export interface ISlotRendererParams {
  slot: Slot;
  slots: Slot[];
  actived?: Slot;
}
export interface ISlotRenderer {
  (p: ISlotRendererParams): React.ReactNode
}
export interface IWorkspacesViewProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
  _ref?: Ref<IWorkspacesViewRef>;
  children?: ISlotRenderer;
  on_slots_changed?(slots: Slot[]): void;

  actived_slot?: Slot;
  on_slot_actived?(slot: Slot): void;
}
export function WorkspacesView(props: IWorkspacesViewProps): React.ReactElement {
  const { children, _ref, on_slots_changed, on_slot_actived, actived_slot, ..._p } = props

  const ref_ele = useRef<HTMLDivElement | null>(null);
  const [workspaces, set_workspaces] = useState<Workspaces<DomAdapter> | null>(null);
  const [slots, set_slots] = useState<Slot[]>([]);

  const ref_on_slot_actived = useRef(on_slot_actived)
  ref_on_slot_actived.current = on_slot_actived

  const handle_slot_actived = useCallback((slot: Slot) => {
    ref_on_slot_actived.current?.(slot)
  }, [])

  useEffect(() => {
    const style = styling(e => e.setAttribute('stay_at_bottom', '1'))
      .override('cell', {
        position: 'absolute',
        overflow: 'hidden',
      })
      .override('line_and_crossdot', {
        backgroundColor: 'rgb(0,120,212)',
        transitionDelay: 0,
        transitionDuration: 100,
        zIndex: 2
      })
      .build()
    style.mount();
    return () => { style.unmount() }
  }, [])

  useEffect(() => {
    const set_ref = (workspaces: Workspaces<DomAdapter> | null) => {
      if (typeof _ref === 'function') _ref({ workspaces })
      else if (_ref) _ref.current = { workspaces };
    }
    const element = ref_ele.current;
    if (!element) {
      set_ref(null)
      set_workspaces(null)
      return
    }
    const adapter = new MyDomAdapter(element)
    const workspaces = new Workspaces(adapter, { id: 'root_slot', type: 'h', keep: true })
    workspaces.on_leaves_changed = () => {
      const slots: Slot[] = []
      for (const leaf of workspaces.leaves) {
        const cell = adapter.get_cell(leaf)
        if (cell && !cell.parentElement) adapter.container.appendChild(cell)
        slots.push(leaf)
      }
      set_slots(slots)
      on_slots_changed?.(slots)
    }
    set_ref(workspaces)
    set_workspaces(workspaces)
    return () => workspaces.release()
  }, [ref_ele, MyDomAdapter, Workspaces])

  const cell_renders = useMemo(() => {
    if (!workspaces || !children) return void 0;
    return slots.map((slot) => {
      const cell = workspaces.adapter.get_cell(slot)
      if (!cell) return void 0;
      const p: ISlotRendererParams = { slot, actived: actived_slot, slots }
      const i = <div onClick={() => handle_slot_actived(slot)} style={{ width: `100%`, height: `100%` }}>
        <ErrorBoundary key={slot.id}>
          {children(p)}
        </ErrorBoundary>
      </div>
      return createPortal(i, cell, slot.id)
    }).filter(Boolean)
  }, [workspaces, slots, children, actived_slot])

  return <>
    <div ref={ref_ele} {..._p} />
    {cell_renders}
  </>
}